package com.open.free.generator.project;

import com.alibaba.druid.sql.SQLUtils;
import com.alibaba.druid.sql.ast.SQLStatement;
import com.alibaba.druid.sql.dialect.mysql.visitor.MySqlSchemaStatVisitor;
import com.alibaba.druid.util.JdbcConstants;
import com.open.free.generator.constant.TemplateConstants;
import com.open.free.generator.entity.Columns;
import com.open.free.generator.entity.EntityMulti;
import com.open.free.generator.entity.SearchKey;
import com.open.free.generator.entity.Source;
import com.open.free.generator.service.ISourceService;
import com.open.free.generator.sqlParser.ConditionExpr;
import com.open.free.generator.sqlParser.DynamicParamSqlEnhancer;
import com.open.free.generator.utils.FileIOUtils;
import com.open.free.generator.utils.FreemarkerUtils;
import com.open.free.generator.vo.SqlArgsVo;
import freemarker.template.TemplateException;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.io.File;
import java.io.IOException;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * @author Faye.Wang
 * @version 1.0
 * @date 2021/1/7 10:43
 * @Description
 */
@Component
public class CodeGenerator {

    @Autowired
    private FreemarkerUtils freemarkerUtils;
    @Autowired
    private ISourceService iSourceService;


    /**
     * 生成entity
     * @param columns
     * @param entityTemplate
     * @param tableName
     * @param entityName
     * @param packageName
     * @param filePath
     * @throws Exception
     */
    public void createEntity(List<Columns> columns,String entityTemplate,String tableName,String entityName,
                             String packageName,String filePath) throws Exception{
        Map<String,Object> dataMaps = new HashMap<>();
        dataMaps.put("columns",columns);
        dataMaps.put("tableName",tableName);
        dataMaps.put("entityName",entityName);
        dataMaps.put("packageName",packageName);
        String content =  freemarkerUtils.processTemplateIntoString(entityTemplate,dataMaps);

        String targetPath = filePath+ File.separator + FileIOUtils.getPackagePath(packageName)+File.separator+"entity";

        FileIOUtils.createFile(content,targetPath,entityName+ TemplateConstants.JAVA_FILE_SUFFIX);
    }

    public void createVo(List<Columns> columns,String entityTemplate,String entityName,String packageName,String filePath) throws Exception{
        Map<String,Object> dataMaps = new HashMap<>();
        dataMaps.put("columns",columns);
        dataMaps.put("entityName",entityName);
        dataMaps.put("packageName",packageName);
        dataMaps.put("packageCoreName", StringUtils.substringBeforeLast(packageName,"."));
        String content =  freemarkerUtils.processTemplateIntoString(entityTemplate,dataMaps);
        String targetPath = filePath+ File.separator + FileIOUtils.getPackagePath(packageName)+File.separator+"vo";

        FileIOUtils.createFile(content,targetPath,entityName+"Vo"+ TemplateConstants.JAVA_FILE_SUFFIX);
    }


    public void createDto(List<Columns> columns,String entityTemplate,String entityName,String packageName,String filePath
                          ) throws Exception{
        Map<String,Object> dataMaps = new HashMap<>();
        dataMaps.put("columns",columns);
        dataMaps.put("entityName",entityName);
        dataMaps.put("packageName",packageName);

        String content =  freemarkerUtils.processTemplateIntoString(entityTemplate,dataMaps);
        String targetPath = filePath+ File.separator + FileIOUtils.getPackagePath(packageName)+File.separator+"dto";

        FileIOUtils.createFile(content,targetPath,entityName+"DTO"+ TemplateConstants.JAVA_FILE_SUFFIX);
    }

    public void createMultiDto(List<Columns> multiDto,String entityTemplate,String entityName,String packageName,String filePath
                          ) throws Exception{
        Map<String,Object> dataMaps = new HashMap<>();
        dataMaps.put("columns",multiDto);
        dataMaps.put("entityName",entityName+"Multi");
        dataMaps.put("packageName",packageName);

        String content =  freemarkerUtils.processTemplateIntoString(entityTemplate,dataMaps);
        String targetPath = filePath+ File.separator + FileIOUtils.getPackagePath(packageName)+File.separator+"dto";

        FileIOUtils.createFile(content,targetPath,entityName+"MultiDTO"+ TemplateConstants.JAVA_FILE_SUFFIX);
    }



    public void createMapper(String entityTemplate,String entityName,String packageName,String filePath,boolean flag,String singleSql,String dtoFlag)throws Exception{
        Map<String,Object> dataMaps = new HashMap<>();

        dataMaps.put("entityName",entityName);
        dataMaps.put("packageName",packageName);
        dataMaps.put("singleSqlFlag",flag);
        dataMaps.put("singleSql",singleSql);
        dataMaps.put("dtoFlag",dtoFlag);
        String content =  freemarkerUtils.processTemplateIntoString(entityTemplate,dataMaps);
        String targetPath = filePath+ File.separator + FileIOUtils.getPackagePath(packageName)+File.separator+"mapper";

        FileIOUtils.createFile(content,targetPath,entityName+"Mapper"+ TemplateConstants.JAVA_FILE_SUFFIX);
    }
    public void createMapperXml(String entityName,String packageName,String filePath,boolean flag,String singleSql,String dtoFlag) throws Exception{
        Map<String,Object> dataMaps = new HashMap<>();
        dataMaps.put("entityName",entityName);
        dataMaps.put("packageName",packageName);
        dataMaps.put("singleSqlFlag",flag);
        dataMaps.put("singleSql",singleSql);
        dataMaps.put("dtoFlag",dtoFlag);
        String content =  freemarkerUtils.processTemplateIntoString(TemplateConstants.CODE_GENERATOR_MAPPER_XML,dataMaps);
        String targetPath = filePath+ File.separator + FileIOUtils.getPackagePath(packageName)+File.separator+"mapper";
        FileIOUtils.createFile(content,targetPath,entityName+"Mapper"+TemplateConstants.XML_FILE_SUFFIX);
    }

    public void createMultiMapperXml(List<String> entityList,String packageName,String filePath,String mainTable,String sql,String multiSql) throws Exception{

        for (String item : entityList) {
            String entityName ="";
            String tmpMainTable = "";
            if(item.contains("#")){
                entityName = item.split("#")[1];
                tmpMainTable = item.split("#")[0];
            }else{
                entityName = FileIOUtils.clazzName(item);
                tmpMainTable = item;
            }

            Map<String, Object> dataMaps = new HashMap<>();
            dataMaps.put("entityName", entityName);
            dataMaps.put("packageName", packageName);
            if(tmpMainTable.equals(mainTable)){
                dataMaps.put("multiFlag", true);
                dataMaps.put("multiSelectSql", sql);
                dataMaps.put("entityDTO", entityName+"DTO");
                dataMaps.put("entityMultiDTO", entityName+"MultiDTO");
                dataMaps.put("multiSelectListSql", multiSql);
            }
            dataMaps.put("singleSqlFlag", false);

            String content = freemarkerUtils.processTemplateIntoString(TemplateConstants.CODE_GENERATOR_MAPPER_XML, dataMaps);
            String targetPath = filePath + File.separator + FileIOUtils.getPackagePath(packageName) + File.separator + "mapper";
            FileIOUtils.createFile(content, targetPath, entityName + "Mapper" + TemplateConstants.XML_FILE_SUFFIX);
        }
    }


    public void createMultiMapper(List<String> entityList,String entityTemplate,String packageName,String filePath,String mainTable)throws Exception{
        for (String item : entityList) {
            Map<String, Object> dataMaps = new HashMap<>();
            String entityName ="";
            String tmpMainTable = "";
            if(item.contains("#")){
                entityName = item.split("#")[1];
                tmpMainTable = item.split("#")[0];
            }else{
                entityName = FileIOUtils.clazzName(item);
                tmpMainTable = item;
            }
            dataMaps.put("entityName", entityName);
            dataMaps.put("packageName", packageName);
            if(tmpMainTable.equals(mainTable)){
                dataMaps.put("multiFlag", true);
                dataMaps.put("entityDTO", entityName+"DTO");
                dataMaps.put("entityMultiDTO", entityName+"MultiDTO");
            }
            String content = freemarkerUtils.processTemplateIntoString(entityTemplate, dataMaps);
            String targetPath = filePath + File.separator + FileIOUtils.getPackagePath(packageName) + File.separator + "mapper";

            FileIOUtils.createFile(content, targetPath, entityName + "Mapper" + TemplateConstants.JAVA_FILE_SUFFIX);
        }
    }



    public void createController(String entityTemplate,String entityName,String packageName,String filePath,String httpUrl)throws Exception{
        Map<String,Object> dataMaps = new HashMap<>();
        dataMaps.put("httpUrl",httpUrl);
        dataMaps.put("entityName",entityName);
        dataMaps.put("packageName",packageName);
        dataMaps.put("packageCoreName", StringUtils.substringBeforeLast(packageName,"."));
        String content =  freemarkerUtils.processTemplateIntoString(entityTemplate,dataMaps);
        String targetPath = filePath+ File.separator + FileIOUtils.getPackagePath(packageName)+File.separator+"controller";

        FileIOUtils.createFile(content,targetPath,entityName+"Controller"+ TemplateConstants.JAVA_FILE_SUFFIX);
    }



    public void createService(String entityName,String packageName,String filePath,String searchKey,String dtoFlag,
                              boolean singleSqlFlag,String searchSql, List<SqlArgsVo> sqlArgs)throws Exception{

        String servicePath = filePath+ File.separator + FileIOUtils.getPackagePath(packageName)+File.separator+"service";
        String serviceImplPath = filePath+ File.separator + FileIOUtils.getPackagePath(packageName)+File.separator+"service"+File.separator+"impl";
        Map<String,Object> dataMaps = new HashMap<>();
        dataMaps.put("entityNameVar",toUpperCaseFirst(entityName));
        dataMaps.put("entityName",entityName);
        dataMaps.put("packageName",packageName);
        dataMaps.put("dtoFlag",dtoFlag);
        dataMaps.put("singleSqlFlag",singleSqlFlag);
        dataMaps.put("singleSql",searchSql);
        dataMaps.put("sqlArgs",sqlArgs);
        dataMaps.put("packageCoreName", StringUtils.substringBeforeLast(packageName,"."));
        List<SearchKey> searchKeys = new ArrayList<>();
        if(StringUtils.isNotBlank(searchKey)){
            String[] array = searchKey.split(",");
            for(String str:array){
                SearchKey sk = new SearchKey();
                sk.setKeyName(str.split("#")[0]);
                sk.setCronName(str.split("#")[1]);
                sk.setBeanName(FileIOUtils.beanName(str.split("#")[0]));
                searchKeys.add(sk);
            }
        }
        dataMaps.put("searchKeys",searchKeys);

        String service =  freemarkerUtils.processTemplateIntoString(TemplateConstants.CODE_GENERATOR_SERVICE,dataMaps);
        String serviceImpl =  freemarkerUtils.processTemplateIntoString(TemplateConstants.CODE_GENERATOR_SERVICE_IMPL,dataMaps);

        FileIOUtils.createFile(service,servicePath,"I"+entityName+"Service"+ TemplateConstants.JAVA_FILE_SUFFIX);
        FileIOUtils.createFile(serviceImpl,serviceImplPath,"I"+entityName+"ServiceImpl"+ TemplateConstants.JAVA_FILE_SUFFIX);
    }






    /**
     * 将列明首字母大写 ColumName
     *
     * @param columnName
     * @return
     */
    private String toUpperCaseFirst(String columnName) {
        return columnName.substring(0, 1).toLowerCase() + columnName.substring(1, columnName.length());
    }


    /**
     * 多表controller
     * @param entityTemplate
     * @param entityName
     * @param packageName
     * @param filePath
     * @param httpUrl
     * @throws Exception
     */
    public void createMultiController(List<String> entityList, String entityTemplate,String entityName,String packageName,String filePath,String httpUrl)throws Exception{
        Map<String,Object> dataMaps = new HashMap<>();
        List<String> argsEntity = new ArrayList<>();
        List<EntityMulti> entityMultis = new ArrayList<>();
        for (String item : entityList) {
            String[] entitys = item.split("#");
            String mName = entitys[0];
            EntityMulti entityMulti = new EntityMulti();
            String className = FileIOUtils.clazzName(mName);
            entityMulti.setEntityName(className);
            entityMulti.setMapperVar(FileIOUtils.clazzVarName(mName));
            argsEntity.add(FileIOUtils.clazzVarName(mName));
            entityMultis.add(entityMulti);
        }
        String[] argsArrays = argsEntity.toArray(new String[argsEntity.size()]);
        String methodArgs = StringUtils.join(argsArrays, ",");
        dataMaps.put("methodArgs",methodArgs);
        dataMaps.put("httpUrl",httpUrl);
        dataMaps.put("entityName",entityName);
        dataMaps.put("packageName",packageName);
        dataMaps.put("entityMappers", entityMultis);
        dataMaps.put("entityMultiDTO", entityName+"MultiDTO");
        dataMaps.put("packageCoreName", StringUtils.substringBeforeLast(packageName,"."));
        String content =  freemarkerUtils.processTemplateIntoString(entityTemplate,dataMaps);
        String targetPath = filePath+ File.separator + FileIOUtils.getPackagePath(packageName)+File.separator+"controller";

        FileIOUtils.createFile(content,targetPath,entityName+"Controller"+ TemplateConstants.JAVA_FILE_SUFFIX);
    }


    /**
     * 多表
     * 生成serviceImpl
     * @param entityList
     */
    public void createMultiService(List<String> entityList, String packageName, String entityName,
                                   String filePath, List<SqlArgsVo> sqlArgs
                                  ) throws IOException, TemplateException {

        String servicePath = filePath+ File.separator + FileIOUtils.getPackagePath(packageName)+File.separator+"service";
        String serviceImplPath = filePath+ File.separator + FileIOUtils.getPackagePath(packageName)+File.separator+"service"+File.separator+"impl";


        List<EntityMulti> entityMultis = new ArrayList<>();
        List<String> argsEntity = new ArrayList<>();
        String pkEntity = "";
        String pkRecord = "";

        for (String item : entityList) {
            String[] entitys = item.split("#");
            String mName = entitys[0];
            String isRel = entitys[1];
            EntityMulti entityMulti = new EntityMulti();
            String className = FileIOUtils.clazzName(mName);
            entityMulti.setEntityName(className);
            entityMulti.setMapperName(className);
            entityMulti.setMapperVar(FileIOUtils.clazzVarName(mName));
            if ("true".equals(isRel)) {
                entityMulti.setRelIdFlag(true);
                entityMulti.setRelId(FileIOUtils.clazzName(entitys[2]));
                entityMulti.setOrgRelId(entitys[2]);
                entityMulti.setRelArgs(pkRecord);
            } else {
                entityMulti.setRelIdFlag(false);
                pkEntity = entitys[2];
                pkRecord = entityMulti.getMapperVar();
            }
            entityMultis.add(entityMulti);
            argsEntity.add(FileIOUtils.clazzName(mName) + " " + FileIOUtils.clazzVarName(mName));
        }

        String[] argsArrays = argsEntity.toArray(new String[argsEntity.size()]);
        String methodArgs = StringUtils.join(argsArrays, ",");
        Map<String, Object> dataMaps = new HashMap<>();
        dataMaps.put("entityMappers", entityMultis);
        dataMaps.put("entityNameVar",toUpperCaseFirst(entityName));
        dataMaps.put("packageCoreName", StringUtils.substringBeforeLast(packageName,"."));
        dataMaps.put("methodArgs", methodArgs);
        dataMaps.put("pkId", pkEntity);
        dataMaps.put("entityDTO", entityName + "DTO");
        dataMaps.put("entityMultiDTO", entityName+"MultiDTO");
        dataMaps.put("entityName",entityName);
        dataMaps.put("packageName",packageName);
        dataMaps.put("sqlArgs",sqlArgs);
        String service =  freemarkerUtils.processTemplateIntoString(TemplateConstants.CODE_GENERATOR_MULTI_SERVICE,dataMaps);
        String serviceImpl =  freemarkerUtils.processTemplateIntoString(TemplateConstants.CODE_GENERATOR_MULTI_SERVICE_IMPL,dataMaps);

        FileIOUtils.createFile(service,servicePath,"I"+entityName+"Service"+ TemplateConstants.JAVA_FILE_SUFFIX);
        FileIOUtils.createFile(serviceImpl,serviceImplPath,"I"+entityName+"ServiceImpl"+ TemplateConstants.JAVA_FILE_SUFFIX);


    }


    private static List<SQLStatement> getSQLStatementList(String sql) {
        String dbType = JdbcConstants.MYSQL;
        return SQLUtils.parseStatements(sql, dbType);
    }

    public String multiSql(String sql){
        // 动态SQL 生成
        DynamicParamSqlEnhancer enhancer = new DynamicParamSqlEnhancer();
        sql = enhancer.enhanceDynamicConditions(sql);
        return sql;
    }

    public List<Columns> multiSqlDto(String sql, Source source){
        List<SQLStatement> sqlStatementList = getSQLStatementList(sql);
        //默认为一条sql语句
        SQLStatement stmt = sqlStatementList.get(0);
        MySqlSchemaStatVisitor visitor = new MySqlSchemaStatVisitor();
        stmt.accept(visitor);

        List<Columns> columnsList = new ArrayList<>();
        // 生成dto
        visitor.getColumns().forEach(item->{
            String table = item.getTable();
            String column = item.getName();
            Columns columns =  iSourceService.getTableInfo(source,table,column);
            columnsList.add(columns);
        });
        DynamicParamSqlEnhancer enhancer = new DynamicParamSqlEnhancer();
        List<ConditionExpr> whereSql = enhancer.parseSqlDynamicConditions(sql);
        whereSql.forEach(item->{
            Columns columns = new Columns();
            String operator = item.getOperator();
            if("IN".equals(operator.toUpperCase())){
                String name = StringUtils.substringAfterLast(item.getParamNames().get(0),".");
                columns.setSqlColumn("String");
                columns.setName(name);
                columns.setColumnComment("");
                columns.setPropertyName(FileIOUtils.toUpperCaseFirst(name));
                columnsList.add(columns);
            }
        });


        return columnsList;
    }




    public static void main(String[] args){
        String regex = "['#{]([\\s\\S]*?)}'";
       String str = "SELECT t1.id,t1.service_line_name,t1.about_team,t1.for_future,t2.ability_title,t2.ability_desc FROM" +
            "t_sub_service_line t1," +
            "t_sub_service_line_ability t2" +
            "WHERE t1.id = t2.sub_service_id AND t1.service_line_name='#{serviceLineName}' and t1.about_team='#{aboutTeam}'";
        getQuestionResolution(regex, str);


    }
    private static void getQuestionResolution(String regex,String html){

        Matcher matcher = Pattern.compile(regex).matcher(html);
        while (matcher.find()){
            System.out.println(matcher.group().trim());
        }
    }


}
